package mgo

import (
	"context"
	"gitee.com/dreamwood/ez-go/ez"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

const int_id_col_name = "ez_int_ids"

type NextId struct {
	Name string `bson:"name"`
	Id   int64  `bson:"id"`
}

func GetNextId(collName string, Db ...*mongo.Database) int64 {
	db := ez.DBMongo
	if len(Db) > 0 {
		db = Db[0]
	}
	if db != nil {
		coll := db.Collection(int_id_col_name)
		r := coll.FindOneAndUpdate(
			context.TODO(),
			bson.D{{"name", collName}},
			bson.D{{"$inc", bson.D{{"id", 1}}}})
		nextid := new(NextId)
		err := r.Decode(&nextid)
		if err != nil {
			ez.LogToConsole(err.Error())
			//创建一条记录
			r, err := coll.InsertOne(context.TODO(), bson.D{{"name", collName}, {"id", 1}})
			if err != nil {
				ez.LogToConsole(err.Error())
				return -1
			} else {
				refreshOneId(collName)
				ez.LogToConsole("初始化数据库的NextId数据", collName, r.InsertedID.(primitive.ObjectID).Hex())
				return GetNextId(collName)
				//return 1
			}
		}
		return nextid.Id
	}
	return -1
}

type simpleDoc struct {
	Id int64 `bson:"id"`
}

func refreshNextId() {
	db := ez.DBMongo
	if db != nil {
		coll := db.Collection(int_id_col_name)
		c, e := coll.Find(
			context.TODO(),
			bson.D{})
		if e != nil {
			ez.LogToConsole(e.Error())
			return
		}
		nextids := make([]*NextId, 0)
		err := c.All(context.TODO(), &nextids)
		if err != nil {
			ez.LogToConsole(err.Error())
			return
		}
		for _, nextid := range nextids {
			col := db.Collection(nextid.Name)
			opt := options.FindOneOptions{
				Sort: bson.D{{"id", -1}},
			}
			sd := new(simpleDoc)
			col.FindOne(context.TODO(), bson.D{}, &opt).Decode(&sd)
			if sd.Id > 0 {
				//todo 销毁数据后，如果重启服务，会导致ID回滚
				err1 := coll.FindOneAndUpdate(
					context.TODO(),
					bson.D{{"name", nextid.Name}},
					bson.D{{"$set", bson.D{{"id", sd.Id + 1}}}})
				if err1.Err() != nil {
					ez.LogToConsole(err1.Err().Error())
					return
				}
			}
		}
	}
}

func refreshOneId(collName string) {
	db := ez.DBMongo
	coll := db.Collection(int_id_col_name)
	col := db.Collection(collName)
	opt := options.FindOneOptions{
		Sort: bson.D{{"id", -1}},
	}
	sd := new(simpleDoc)
	col.FindOne(context.TODO(), bson.D{}, &opt).Decode(&sd)
	if sd.Id > 0 {
		err1 := coll.FindOneAndUpdate(
			context.TODO(),
			bson.D{{"name", collName}},
			bson.D{{"$set", bson.D{{"id", sd.Id + 1}}}})
		if err1.Err() != nil {
			ez.LogToConsole(err1.Err().Error())
			return
		}
	}
}

func init() {
	ez.Subscribe(ez.EventAfterServerRun, func(v interface{}, ctx context.Context) {
		refreshNextId()
	})
}
